 /*
  *    Copyright © OpenAtom Foundation.
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
  *    You may obtain a copy of the License at
  *
  *         http://www.apache.org/licenses/LICENSE-2.0
  *
  *    Unless required by applicable law or agreed to in writing, software
  *    distributed under the License is distributed on an "AS IS" BASIS,
  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *    See the License for the specific language governing permissions and
  *    limitations under the License.
  */

 package com.inspur.edp.bef.bizentity.util;


 import com.inspur.edp.bef.bizentity.GspBizEntityElement;
 import com.inspur.edp.cef.designtime.api.IGspCommonField;
 import com.inspur.edp.cef.designtime.api.collection.GspAssociationCollection;
 import com.inspur.edp.cef.designtime.api.element.*;
 import com.inspur.edp.cef.designtime.api.entity.MappingInfo;
 import com.inspur.edp.cef.designtime.api.entity.MappingRelation;
 import com.inspur.edp.das.commonmodel.IGspCommonElement;
 import com.inspur.edp.das.commonmodel.entity.element.GspCommonAssociation;
 import com.inspur.edp.udt.designtime.api.entity.ComplexDataTypeDef;
 import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
 import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
 import com.inspur.edp.udt.designtime.api.entity.dbInfo.ColumnInfo;
 import com.inspur.edp.udt.designtime.api.entity.dbInfo.ColumnMapType;
 import com.inspur.edp.udt.designtime.api.entity.element.UdtElement;
 import com.inspur.edp.udt.designtime.api.entity.enumtype.UseType;
 import java.util.UUID;
 import lombok.var;

 /**
  * 更新udt字段
  */
 public class UpdateBeElementUtil {

   /**
    * 创建字段实例
    *
    * @return
    */
   private GspBizEntityElement GetChildElement() {
     GspBizEntityElement tempVar = new GspBizEntityElement();
     tempVar.setID(UUID.randomUUID().toString());
     return tempVar;
   }

   /**
    * 根据引用的udt元数据更新字段(模板约束均更新)
    *
    * @param element
    * @param udt
    */
   //ORIGINAL LINE: public void updateElementWithRefUdt(GspBizEntityElement element, UnifiedDataTypeDef udt, bool isFirstChoose = false)
   public final void updateElementWithRefUdt(GspBizEntityElement element, UnifiedDataTypeDef udt,
       boolean isFirstChoose) {
     element.setUdtID(udt.getId());
     element.setUdtName(udt.getName());

     Object tempVar = element.getMappingRelation().clone();

     var mappingInfos = (MappingRelation) ((tempVar instanceof MappingRelation) ? tempVar : null);

     var childElements = element.getChildElements().clone(null, null);

     element.getMappingRelation().clear();
     element.getChildElements().clear();

     if (udt.getColumns().size() > 0) {

       for (ColumnInfo col : udt.getColumns()) {

         String columnInfoId = col.getID();
         MappingInfo mappingInfo = new MappingInfo();
         GspBizEntityElement childElement = new GspBizEntityElement();
         if (mappingInfos != null && mappingInfos.getValues().contains(columnInfoId)) {
           // ① childElement已存在，更新；
           for (MappingInfo info : mappingInfos) {
             if (info.getValueInfo().equals(columnInfoId)) {
               mappingInfo = info;
               break;
             }
           }
           String childElementId = mappingInfo.getKeyInfo();
           for (IGspCommonField commonField : childElements) {
             if (commonField.getID().equals(childElementId)) {
               childElement = (GspBizEntityElement) ((commonField instanceof GspBizEntityElement)
                   ? commonField : null);
               break;
             }
           }
           if (childElement == null) {
             throw new RuntimeException(
                 "字段映射关系中的id=" + childElementId + "的+" + childElement + "不存在");
           }
         } else {
           // ② 新增
           childElement = GetChildElement();
           MappingInfo tempVar3 = new MappingInfo();
           tempVar3.setKeyInfo(childElement.getID());
           tempVar3.setValueInfo(columnInfoId);
           mappingInfo = tempVar3;
         }
         // 根据columnInfo更新childElement
         MapColumnInfoToField(col, element.getLabelID(), childElement);

         element.getMappingRelation().add(mappingInfo);
         element.getChildElements().add(childElement);
       }
     }

     // 字段设置为udt,清空已有标记，带出当前单值udt的标记
     if (element.getBeLabel() != null && element.getBeLabel().size() > 0) {
       element.getBeLabel().clear();
     }

     // 其他属性
     if (udt instanceof ComplexDataTypeDef) {
       updateComplexDataTypeDefProperties(element, (ComplexDataTypeDef) udt);
     } else if (udt instanceof SimpleDataTypeDef) {
       updateSimpleDataTypeDefProperties(element, (SimpleDataTypeDef) udt, isFirstChoose);
     }
   }

   /**
    * 转换columnInfo为childElement
    *
    * @param info
    * @param prefix
    * @param ele    映射字段
    * @return
    */
   public final void MapColumnInfoToField(ColumnInfo info, String prefix, GspBizEntityElement ele) {
     if (StringUtil.checkNull(prefix)) {
       throw new RuntimeException("请先完善当前字段的[编号]及[标签]。");
     }

     var newLabelId = prefix + "_" + info.getCode();
     ele.setLabelID(newLabelId);
     ele.setCode(newLabelId);
     ele.setName(info.getName());
     ele.setMDataType(info.getMDataType());
     ele.setDefaultValue(info.getDefaultValue());
     ele.setLength(info.getLength());
     ele.setPrecision(info.getPrecision());
   }

   //#region 单值

   /**
    * 根据单值udt更新字段的其他属性
    *
    * @param element
    * @param sUdt
    * @param isFirstChoose 是否首次选择
    */
   private void updateSimpleDataTypeDefProperties(GspBizEntityElement element,
       SimpleDataTypeDef sUdt, boolean isFirstChoose) {
     if (StringUtil.checkNull(element.getCode())) {
       element.setCode(sUdt.getCode());
     }
     if (StringUtil.checkNull(element.getName())) {
       element.setName(sUdt.getName());
     }

     if (isFirstChoose || isConstraint(sUdt, "DataType")) {
       element.setMDataType(sUdt.getMDataType());
     }
     if (isFirstChoose || isConstraint(sUdt, "Length")) {
       element.setLength(sUdt.getLength());
     }
     if (isFirstChoose || isConstraint(sUdt, "Precision")) {
       element.setPrecision(sUdt.getPrecision());
     }
     if (isFirstChoose || isConstraint(sUdt, "ObjectType")) {
       element.setObjectType(sUdt.getObjectType());
       // 关联
       if (element.getChildAssociations() == null) {
         element.setChildAssociations(new GspAssociationCollection());
       }

       var belongElement =
           (element.getChildAssociations() != null && element.getChildAssociations().size() > 0)
               ? element.getChildAssociations().get(0).getBelongElement() : null;

       var assos = element.getChildAssociations().clone(belongElement);

       element.getChildAssociations().clear();
       if (sUdt.getChildAssociations() != null && sUdt.getChildAssociations().size() > 0) {
         for (GspAssociation item : sUdt.getChildAssociations()) {

// 					var beAsso = assos.Find(asso { return asso.Id == item.Id);
           GspAssociation beAsso = assos.stream().filter((asso) -> {
             return item.getId().equals(asso.getId());
           }).findFirst().orElse(null);
           element.getChildAssociations()
               .add(convertUdtAssociation(item, element, beAsso, isFirstChoose));
         }
       }

       element.setEnumIndexType(sUdt.getEnumIndexType());
       // 枚举
       element.getContainEnumValues().clear();
       if (sUdt.getContainEnumValues() != null && sUdt.getContainEnumValues().size() > 0) {
         for (GspEnumValue item : sUdt.getContainEnumValues()) {
           element.getContainEnumValues().add(item);
         }
       }
     }
     if (isFirstChoose || isConstraint(sUdt, "DefaultValue")) {
       element.setDefaultValue(
           (sUdt.getDefaultValue() == null) ? null : sUdt.getDefaultValue().toString());
     }
     if (isFirstChoose || isConstraint(sUdt, "IsRequired")) {
       element.setIsRequire(sUdt.getIsRequired());
     }
     // 标记
     element.setBeLabel(sUdt.getBeLabel());
   }

   /**
    * 是否约束
    *
    * @return
    */
   private boolean isConstraint(SimpleDataTypeDef sUdt, String propertyName) {
     if (sUdt.getPropertyUseTypeInfos().containsKey(propertyName)) {

       var type = sUdt.getPropertyUseTypeInfos().get(propertyName);
       return type.getPropertyUseType() == UseType.AsConstraint;
     } else {
       throw new RuntimeException("单值业务字段的约束信息中无属性名" + propertyName);
     }
   }

   //#endregion

   //#region 多值

   /**
    * 根据多值udt更新字段的其他属性
    *
    * @param element
    * @param cUdt
    */
   private void updateComplexDataTypeDefProperties(GspBizEntityElement element,
       ComplexDataTypeDef cUdt) {
     if (StringUtil.checkNull(element.getCode())) {
       element.setCode(cUdt.getCode());
     }
     if (StringUtil.checkNull(element.getName())) {
       element.setName(cUdt.getName());
     }

     UdtElement newElement;
     if (cUdt.getElements().size() == 1
         && cUdt.getDbInfo().getMappingType() != ColumnMapType.SingleColumn) {
       newElement = (UdtElement) cUdt.getElements().get(0);
     } else {
       newElement = new UdtElement(cUdt.getPropertys());
     }

     element.setObjectType(newElement.getObjectType());
     // 若为[单一列]的映射关系，可能导致超长，需把数据类型改为[Text]
     if (cUdt.getDbInfo().getMappingType() == ColumnMapType.SingleColumn) {
       element.setMDataType(GspElementDataType.Text);
       element.setLength(0);
       element.setPrecision(0);
     } else {
       element.setMDataType(newElement.getMDataType());
       element.setLength(newElement.getLength());
       element.setPrecision(newElement.getPrecision());
     }
     element.setDefaultValue(newElement.getDefaultValue());
     element.getChildAssociations().clear();
     element.getContainEnumValues().clear();
   }

   //#endregion


   //#region 关联
   private GspAssociation convertUdtAssociation(GspAssociation udtAsso, IGspCommonElement ele,
       GspAssociation beAsso, boolean isFirstChoose) {
     GspCommonAssociation asso = new GspCommonAssociation();
     asso.setId(udtAsso.getId());
     asso.setRefModel(
         (ele.getBelongObject() == null) ? null : ele.getBelongObject().getBelongModel());
     asso.setRefModelCode(udtAsso.getRefModelCode());
     asso.setRefModelID(udtAsso.getRefModelID());
     ;
     asso.setRefModelName(udtAsso.getRefModelName());
     asso.setRefModelPkgName(udtAsso.getRefModelPkgName());
     asso.setRefObjectCode(udtAsso.getRefObjectCode());
     asso.setRefObjectID(udtAsso.getRefObjectID());
     asso.setRefObjectName(udtAsso.getRefObjectName());
     asso.setForeignKeyConstraintType(udtAsso.getForeignKeyConstraintType());
     asso.setAssoModelInfo(udtAsso.getAssoModelInfo());
     if (udtAsso.getKeyCollection().size() > 0) {
       for (GspAssociationKey key : udtAsso.getKeyCollection()) {
         asso.getKeyCollection().add(convertUdtAssoKey(key, ele));
       }
     }

     if (isFirstChoose) {
       if (udtAsso.getRefElementCollection().size() > 0) {
         for (IGspCommonField refEle : udtAsso.getRefElementCollection()) {
           IGspCommonElement newRefEle = convertUdtRefElement((UdtElement) refEle,
               ele.getLabelID());
           newRefEle.setBelongObject(ele.getBelongObject());
           asso.getRefElementCollection().add(newRefEle);
         }
       }
     } else {

       var udtRefElements = udtAsso.getRefElementCollection().clone(null, udtAsso);
       // udt带出
       if (beAsso != null && beAsso.getRefElementCollection() != null
           && beAsso.getRefElementCollection().size() != 0) {
         for (IGspCommonField refEle : beAsso.getRefElementCollection()) {
           if (refEle.getIsFromAssoUdt()) {
             IGspCommonField refElement = udtRefElements.stream().filter((item) -> {
               return item.getRefElementId().equals(refEle.getRefElementId());
             }).findFirst().orElse(null);
// 						var refElement = udtRefElements.f.Find(item { return item.RefElementId == refEle.getRef);
             udtRefElements.remove(refElement);
             // udt仍包含，则加上；udt上已删，则不加。
             if (refElement != null) {
               IGspCommonElement refEle2 = convertUdtRefElement((UdtElement) refElement,
                   ele.getLabelID());
               refEle2.setID(refEle.getID());
               refEle2.setBelongObject(ele.getBelongObject());
               asso.getRefElementCollection().add(refEle2);
             }
           } else {
             asso.getRefElementCollection().add(refEle);
           }
         }
       }
       if (udtRefElements.size() > 0) {
         for (IGspCommonField refEle : udtRefElements) {
           asso.getRefElementCollection().add(
               convertUdtRefElement((UdtElement) ((refEle instanceof UdtElement) ? refEle : null),
                   ele.getLabelID()));
         }
       }
     }

     return asso;
   }

   private GspAssociationKey convertUdtAssoKey(GspAssociationKey udtKey, IGspCommonElement ele) {
     GspAssociationKey key = new GspAssociationKey();
     key.setSourceElement(udtKey.getSourceElement());
     key.setSourceElementDisplay(udtKey.getSourceElementDisplay());
     key.setTargetElement(ele.getID());
     key.setTargetElementDisplay(ele.getName());
     return key;
   }

   private IGspCommonElement convertUdtRefElement(UdtElement udtEle, String prefix) {
     GspBizEntityElement bizEle = new GspBizEntityElement();
     //bizEle.getID() = udtEle.getID();

     var newLabelId = prefix + "_" + udtEle.getLabelID();
     bizEle.setLabelID(newLabelId);
     bizEle.setCode(udtEle.getCode());
     bizEle.setName(udtEle.getName());
     bizEle.setMDataType(udtEle.getMDataType());
     bizEle.setObjectType(udtEle.getObjectType());
     bizEle.setLength(udtEle.getLength());
     bizEle.setPrecision(udtEle.getPrecision());
     bizEle.setRefElementId(udtEle.getRefElementId());
     bizEle.setIsRefElement(true);
     bizEle.setIsFromAssoUdt(true);

     // udt相关
     bizEle.setIsUdt(udtEle.getIsUdt());
     bizEle.setUdtID(udtEle.getUdtID());
     bizEle.setUdtName(udtEle.getUdtName());
     bizEle.setUdtPkgName(udtEle.getUdtPkgName());
     switch (udtEle.getObjectType()) {
       case Enum:
         bizEle.setContainEnumValues(udtEle.getContainEnumValues());
         break;
     }
     return bizEle;
   }

   //#endregion
 }
